package com.rd.teacher.jichao.day14;

public class TestSingleton {

//    private Singleton1(){}
//
//    private static Singleton1 instance;
//
//    public static Singleton1 getInstance(){
//        // 只有在第一次调用时被创建  后续调用直接返回
//        if(instance == null){
//            instance = new Singleton1();
//        }
//        return instance;
//    }

    private TestSingleton() {
    }

    // 当确保线程只会创建一个单例对象时，同时也要确保多线程之间是可见的
    // 同时希望底层不会进行指令重排序
    private volatile static TestSingleton singleton;

    // 可以在方法上增加synchronized  使得多个线程排队获取
    // 可以实现线程安全  但是在创建完对象后  每次获取对象也还要排队
    // 相对的性能较低
//    public static synchronized TestSingleton getInstance() {
//        // 在获取单例对象时可能多个线程都获取为null
//        // 此时会创建出多个实例来
//        if (singleton == null) {
//            singleton = new TestSingleton();
//        }
//        return singleton;
//    }

    // 如果在方法体内加锁  实际是对类加锁
    // 如果只对创建实例部分加锁  可能其他线程直接走到获取实例的代码
    // 此时实例还未创建  会返回空的实例
    public static TestSingleton getInstance1() {
        // 在获取单例对象时可能多个线程都获取为null
        // 此时会创建出多个实例来
        if (singleton == null) {
            synchronized (TestSingleton.class) {
                singleton = new TestSingleton();
            }
        }
        return singleton;
    }

    // 线程1执行第40行判断时，可能线程2已经获取到了锁，执行42行，正在创建对象
    // 当线程2创建完对象释放锁以后，线程1获取到锁，又要创建对象
    // 我们在进入到锁之后，再判断一次，避免这个问题
    // 这个方式叫做双重检查
    public static TestSingleton getInstance() {
        // 在获取单例对象时可能多个线程都获取为null
        // 此时会创建出多个实例来
        if (singleton == null) {
            synchronized (TestSingleton.class) {
                if (singleton == null) {
                    singleton = new TestSingleton();
                }
            }
        }
        return singleton;
    }
}
